import { Injectable } from '@nestjs/common';
import * as Minio from 'minio';
import * as process from 'process';

import { getContentType } from '@/utils';
import { Logger } from '@/utils/log4js';

export enum UPLOAD_STATE {
  OK = 1,
  ERROR = 0,
}

export enum ACCESS_STATE {
  OK = 0,
  FILE_NOT_FOUND = 1,
  BUCKET_ERROR = 2,
}

@Injectable()
export class NestMinioClientService {
  minioClient: Minio.Client;
  bucketName: string;

  constructor() {
    this.minioClient = new Minio.Client({
      endPoint: process.env.MINIO_ENDPOINT,
      port: parseInt(process.env.MINIO_PORT),
      useSSL: process.env.MINIO_USE_SSL === 'true',
      accessKey: process.env.MINIO_ACCESS_KEY,
      secretKey: process.env.MINIO_SECRET_KEY,
    });
    this.bucketName = process.env.MINIO_BUCKET_NAME;
  }

  getClient(): Minio.Client {
    return this.minioClient;
  }

  /**
   * 上传文件
   * @param fileName {string} 文件名
   * @param file {Buffer} 文件
   * @returns {Promise<void>}
   */
  async uploadFile(fileName: string, file: Buffer): Promise<string> {
    if (!fileName) {
      Logger.error('文件名不能为空');
      return '文件名不能为空';
    }
    if (!this.minioClient) {
      Logger.fatal('Minio client is not initialized');
      return 'Minio异常，请联系管理员😁';
    }
    // 检查 bucket 是否存在
    const bucketExists = await this.minioClient.bucketExists(this.bucketName);
    // 如果不存在，则创建
    if (!bucketExists) {
      await this.minioClient.makeBucket(this.bucketName, 'us-east-1');
    }
    // 获取当前时间,按日期分类存储
    const timePath = new Date().toLocaleDateString().replace(/\//g, '-');
    // 上传文件
    await this.minioClient.putObject(
      this.bucketName,
      `temp/${timePath}/${fileName}`,
      file,
      file.length,
      {
        'Content-Type': getContentType(fileName), // 设置文件类型, 可以进行浏览器端预览
      },
    );
    // 返回文件的 URL
    return `http://${process.env.MINIO_ENDPOINT}:${process.env.MINIO_PORT}/${this.bucketName}/temp/${timePath}/${fileName}`;
  }

  /**
   * 移动文件至 指定文件夹
   * @param fileName {string} 文件名
   * @param folderName {string} 文件夹名
   * @returns {Promise<void>}
   */
  async moveFile(filePath: string) {
    if (!filePath) {
      Logger.error('文件为空，操作失败');
      return '操作失败';
    }
    if (!this.minioClient) {
      Logger.fatal('Minio client is not initialized');
      return 'Minio异常，请联系管理员😁';
    }
    try {
      const sourceFilePath = filePath.replace(/.*temp\//, 'temp/');
      const newFilePath = filePath.replace(/.*temp\//, 'static/');
      // 移动文件
      // 复制文件到新路径
      await this.minioClient.copyObject(
        this.bucketName,
        newFilePath,
        `${this.bucketName}/${sourceFilePath}`,
      );
      // 删除原文件
      await this.minioClient.removeObject(this.bucketName, sourceFilePath);
      return `http://${process.env.MINIO_ENDPOINT}:${process.env.MINIO_PORT}/${this.bucketName}/${newFilePath}`;
    } catch (error) {
      Logger.error(`移动文件失败: ${error}`);
      return '操作失败';
    }
  }

  /**
   * 删除文件
   * @param fileName
   */
  async deleteFile(fileName: string) {
    if (!fileName) {
      Logger.error('文件名不能为空');
      return '文件名不能为空';
    }
    if (!this.minioClient) {
      Logger.fatal('Minio client is not initialized');
      return 'Minio异常，请联系管理员😁';
    }
    try {
      // 删除文件
      await this.minioClient.removeObject(this.bucketName, `temp/${fileName}`);
      Logger.debug(`删除文件成功: ${fileName}`);
      return '删除文件成功';
    } catch (error) {
      Logger.error(`删除文件失败: ${error}`);
      return '删除文件失败';
    }
  }

  /**
   * 获取文件
   * @param fileName {string} 文件名
   * @returns {Promise<File>}
   */
  async getFile(fileName: string) {
    if (!fileName) {
      Logger.error('文件名不能为空');
      return '文件名不能为空';
    }
    if (!this.minioClient) {
      Logger.fatal('Minio client is not initialized');
      return 'Minio异常，请联系管理员😁';
    }
    // 检查 bucket 是否存在
    const bucketExists = await this.minioClient.bucketExists(this.bucketName);
    // 如果不存在，则创建
    if (!bucketExists) {
      await this.minioClient.makeBucket(this.bucketName, 'us-east-1');
    }
    try {
      // 获取文件
      const file = await this.minioClient.getObject(this.bucketName, fileName);
      Logger.debug(`获取文件成功: ${file}`);
      return file;
    } catch (error) {
      Logger.error(`获取文件失败: ${error}`);
      return '获取文件失败';
    }
  }
}
